package com.goldgov.code.service.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.goldgov.code.dao.ModuleDao;
import com.goldgov.code.generate.CodeGenerator;
import com.goldgov.code.generate.impl.FreemarkerGeneratorImpl;
import com.goldgov.code.meta.AuthorInfo;
import com.goldgov.code.meta.FieldInfo;
import com.goldgov.code.meta.ModuleInfo;
import com.goldgov.code.meta.RelationInfo;
import com.goldgov.code.meta.RelationInfo.RelationType;
import com.goldgov.code.service.FieldService;
import com.goldgov.code.service.ModuleService;
import com.goldgov.code.template.Group;
import com.goldgov.code.template.ParamKeyName;
import com.goldgov.code.template.commons.CommonPlugin;
import com.goldgov.code.template.commons.impl.order.OrderByPlugin;
import com.goldgov.code.template.commons.impl.tree.TreePlugin;
import com.goldgov.code.template.impl.BeanLayout;
import com.goldgov.code.template.impl.DaoLayout;
import com.goldgov.code.template.impl.ServiceLayout;
import com.goldgov.code.template.impl.WebLayout;

@Service
public class ModuleServiceImpl implements ModuleService,InitializingBean{
	
	private Log logger = LogFactory.getLog(getClass());
	
    @Autowired
    private ModuleDao moduleDao;
    
	@Autowired
	private FieldService fieldService;
	
	private CodeGenerator generator = new FreemarkerGeneratorImpl();
	
	private Group defaultGroup = new Group();
	
	@Value("${source-code.template-path}")
	private String templatePath;
	
	@Value("${source-code.kdesign-path}")
	private String kdesignPath;
	
	@Value("${source-code.gen-path}")
	private String genPath;
	
	@Value("${server.port:80}")
	private int port;
	
	public ModuleServiceImpl(){
		BeanLayout beanLayout = new BeanLayout();
		DaoLayout daoLayout = new DaoLayout();
		ServiceLayout serviceLayout = new ServiceLayout();
		WebLayout webLayout = new WebLayout();
//		PageLayout pageLayout = new PageLayout();
		
		defaultGroup.setLayouts(beanLayout,daoLayout,serviceLayout,webLayout);
		generator.setPlugins(new CommonPlugin[] {new TreePlugin(),new OrderByPlugin()});
	}
	
    @Override
	public void addModule(ModuleInfo module){
        moduleDao.addModule(module);
        
        FieldInfo[] moduleFileds = module.getFields();
        if(moduleFileds != null && moduleFileds.length > 0) {
        	for (FieldInfo fieldInfo : moduleFileds) {
        		fieldInfo.setModuleID(module.getModuleID());
        		fieldService.addField(fieldInfo);
			}
        }
	}
        
	@Override
	public void updateModule(ModuleInfo module){
        moduleDao.updateModule(module);
	}
	
	@Override
	public void deleteModule(String[] ids){
        moduleDao.deleteModule(ids);
	}
	
	@Override
	public ModuleInfo getModule(String id){
        return moduleDao.getModule(id);
	}
	
	@Override
	public List<ModuleInfo> listModule(String projectID){
        return moduleDao.listModule(projectID);
	}

	@Override
	public long countModule(int firstRow, int maxResult) {
		return moduleDao.countModule(firstRow,maxResult);
	}


	@Override
	public void codeGenerate(String packageName, String[] moduleIDs, File targetPath, AuthorInfo author) {
		codeGenerate(packageName,moduleIDs,targetPath,author,null);
	}
	
	@Override
	public void codeGenerate(String packageName,String[] moduleIDs,File targetPath,AuthorInfo author, Group group,
			Map<String, Object> paramMap) {
		ModuleInfo[] moduleInfos = new ModuleInfo[moduleIDs.length];
		for (int i = 0; i < moduleIDs.length; i++) {
			moduleInfos[i] = moduleDao.getModule(moduleIDs[i]);
			//FIXME
			if(moduleInfos[i].getParentID() != null && !"".equals(moduleInfos[i].getParentID())) {
				ModuleInfo parentModule = moduleDao.getModule(moduleInfos[i].getParentID());
				RelationInfo relationInfo = new RelationInfo(parentModule, RelationType.MANY_TO_ONE);
				relationInfo.setRelationField(parentModule.getPkField().getField());
				moduleInfos[i].setRelation(relationInfo);
			}
		}
		
		if(group == null) {
			group = this.defaultGroup;
		}else if(group.getBasePath() == null){
			group.setBasePath(new File(templatePath));
		}
		
		try {
			group.setAuthor(author);
			generator.generate(packageName, moduleInfos, group, targetPath,paramMap);
			// 生成页面
			if(paramMap.containsKey(ParamKeyName.THEME_STYLE)) {
				Boolean init = (Boolean) paramMap.get(ParamKeyName.PAGE_INIT_STRUCTURE);
				String version = (String) paramMap.get(ParamKeyName.PAGE_VERSION);
				String themeStyle = (String) paramMap.get(ParamKeyName.THEME_STYLE);
				String requestPrefix = (String) paramMap.get(ParamKeyName.REQUEST_PREFIX);
				String moduleID = (String) paramMap.get(ParamKeyName.MODULE_ID);
				
				String genType ;
				if(init) {
					genType = "init";
				}else {
					genType = "create";
				}
				
				requestPrefix = requestPrefix == null? "":requestPrefix;
				
				String[] params = new String[] {kdesignPath,genType,"-s","http://localhost:"+port+"/kdesign/config?id=" + moduleID + "&version=" + version +  "&requestPrefix=" + requestPrefix + "&showModel=" + themeStyle,"-b",version,"-o",targetPath.getPath()};
				if(logger.isInfoEnabled()) {
					logger.info("准备调用前端脚手架进行页面生成:" + Arrays.toString(params));
				}
				
				Process process = Runtime.getRuntime().exec(params);
				
				try(BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))){
					String str = null;
					while((str = reader.readLine()) != null) {
						System.out.println("[gen page] "+str);
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException("代码生成时发生错误",e);
		}
	}

	@Override
	public void addRelationModule(String primaryModuleID, String subModuleID) {
		moduleDao.addRelationModule(primaryModuleID, subModuleID);
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		defaultGroup.setBasePath(new File(templatePath));
	}

	@Override
	public void codeGenerate(String packageName, String[] moduleIDs, File targetPath, AuthorInfo author, Group group) {
		codeGenerate(packageName,moduleIDs,targetPath,author,group,Collections.EMPTY_MAP);
	}
    
}